package ru.mera.aaclog;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.Calendar;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.PersistenceException;
import org.apache.commons.io.FilenameUtils;
import org.apache.myfaces.custom.fileupload.UploadedFile;
import ru.mera.aaclog.db.LogHeader;
import ru.mera.aaclog.db.MessageBody;
import ru.mera.aaclog.db.MessageHeader;
import ru.mera.aaclog.db.MessageXmlBody;
import ru.mera.aaclog.dbdao.GenericDAO;
import ru.mera.aaclog.parser.MessageParser;

/**
 * @version 1.0 24/02/2013
 * @author anavdeev
 */
@ManagedBean
@SessionScoped
public class StartPageBean implements Serializable {

    private static final long serialVersionUID = 1L;

    private String name = "AAC Log Viewer";
    private String sessionName;
    private String fileName;
    private UploadedFile uploadedFile;
    private Integer currentID;
    private String deletedId;

    private final EntityManagerFactory emf;
    private final EntityManager em;
    private GenericDAO<LogHeader> logHeaderDAO;
    {
        emf = Persistence.createEntityManagerFactory("aaclogdb");
        em = emf.createEntityManager();
        logHeaderDAO = new GenericDAO(em);
    }

    public String getSessionName() {
        return sessionName;
    }

    public void setSessionName(String sessionName) {
        this.sessionName = sessionName;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public LogHeader[] getSessionList() {
        if (getDeletedId() != null) {
            try {
                logHeaderDAO.delete(new LogHeader(new Integer(getDeletedId())));
            } catch (Exception e) {
                Logger.getLogger(StartPageBean.class.getName()).log(Level.SEVERE, "Exception occured on row deleting. Message is '{0}'", e.getMessage());
            }
            setDeletedId(null);
        }
        if (logHeaderDAO != null ) {
            return logHeaderDAO.get(LogHeader.GET_ALL).toArray(new LogHeader[0]);
        }
        return new LogHeader[0];
    }

    public String getName() {
            return name;
    }
    public void setName(String name) {
            this.name = name;
    }

    public void submit() throws IOException {
        //byte[] bytes = uploadedFile.getBytes();
        Logger.getLogger(StartPageBean.class.getName()).log(Level.SEVERE, "File type: {0}", uploadedFile.getContentType());
        Logger.getLogger(StartPageBean.class.getName()).log(Level.SEVERE, "File name: {0}", uploadedFile.getName());
        Logger.getLogger(StartPageBean.class.getName()).log(Level.SEVERE, "File size: {0} bytes", uploadedFile.getSize());
        Logger.getLogger(StartPageBean.class.getName()).log(Level.SEVERE, "Session name: {0}", getSessionName());

        LogHeader logHeader = new LogHeader(getSessionName(), 
                Calendar.getInstance().getTime(), 
                FilenameUtils.getName(uploadedFile.getName()));
        logHeaderDAO.insert(logHeader);

        InputStream in = uploadedFile.getInputStream();
        int c, offset = 0, errorCounter = 0, messageCounter = 0;
        StringBuilder str = new StringBuilder();
        MessageParser messageParser = new MessageParser();
        while ((c = in.read()) != -1) {
            str.append((char) c);
            int newOffset = str.indexOf(MessageParser.SIP_MESSAGE_TRACE_TAG, offset);
            if (newOffset != -1 && offset < newOffset) {
                if (offset > 0) {
                    MessageHeader message = messageParser.parse(str.substring(offset - 1, newOffset));
                    message.setLog(logHeader);
                    if (insertOneMessage(messageParser, message) != 0) {
                        errorCounter++;
                        try {
                            logHeader = em.merge(logHeader);
                        } catch (Exception e) {
                            Logger.getLogger(StartPageBean.class.getName()).log(Level.SEVERE, null, e);
                        }
                    } else {
                        messageCounter++;
                    }
                }
                offset = newOffset + 1;
            }
        }

        if (errorCounter==0) {
            FacesContext.getCurrentInstance().addMessage(null, 
                new FacesMessage(String.format("'%d' message%s successfully uploaded.", messageCounter, messageCounter > 1 ? "s" : "")));
        } else {
            FacesContext.getCurrentInstance().addMessage(null, 
                new FacesMessage(String.format("'%d' error%s occured. Please look at server log!", errorCounter, errorCounter > 1 ? "s" : "")));
        }
    }

    public int insertOneMessage(MessageParser header, MessageHeader message) {
        int res = 0;
        if (em.getTransaction().isActive()) {
            Logger.getLogger(StartPageBean.class.getName()).log(Level.SEVERE, "Transaction is ACTIVE. Skip insert operation!");
        } else {
            try {
                // insert message
                em.getTransaction().begin();
                em.persist(message);
                // insert message body
                MessageBody messageBody = new MessageBody();
                messageBody.setValue(header.getRawPackage());
                messageBody.setMessage(message);
                em.persist(messageBody);
                // insert message xml body
                MessageXmlBody messageXml = new MessageXmlBody();
                messageXml.setValue(header.getXmlContext());
                messageXml.setMessage(message);
                em.persist(messageXml);

                em.getTransaction().commit();
            } catch (PersistenceException e) {
                em.getTransaction().rollback();
                res = 1;
                Logger.getLogger(StartPageBean.class.getName()).log(Level.SEVERE, null, e);
            } catch (Exception e) {
                if (em.getTransaction().isActive() ) {
                    em.getTransaction().rollback();
                    res = 2;
                }                    
                Logger.getLogger(StartPageBean.class.getName()).log(Level.SEVERE, null, e);
            }
        }
        return res;
    }

    public UploadedFile getUploadedFile() {
        return uploadedFile;
    }

    public void setUploadedFile(UploadedFile uploadedFile) {
        this.uploadedFile = uploadedFile;
    }


    public Integer getCurrentID() {
        return currentID;
    }

    public void setCurrentID(Integer currentID) {
        this.currentID = currentID;
    }

    public String gotoViewer(LogHeader session) {
        Logger.getLogger(StartPageBean.class.getName()).log(Level.SEVERE, "Session number = {0}", session.getId());
        // HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest(); 
        // request.setAttribute("id", session.getSessionName()); 
        setCurrentID(session.getId());
        return "success";
    }

    public String deleteRow(LogHeader session) {
        Logger.getLogger(StartPageBean.class.getName()).log(Level.SEVERE, "Session number = {0}", session.getId());
        setCurrentID(session.getId());
        return "success";
    }
    
    public void setDeletedId(String deletedId) {
        this.deletedId = deletedId;
    }

    public String getDeletedId() {
        return this.deletedId;
    }
    
    public void createAndDownloadLog(LogHeader session) throws IOException {
        GenericDAO<MessageBody> raw = new GenericDAO(em);
        // TODO: нужно сохранять правильный порядок сообщений для корректной выгрузки
        List<MessageBody> messages = raw.get(MessageBody.GET_BY_LOG, new Integer(session.getId()));

        ByteArrayOutputStream output = new ByteArrayOutputStream();
        for (MessageBody body : messages) {
            output.write(body.getValue().getBytes());
        }
        
        // Prepare report to be downloaded.
        String filename = "out_" + session.getId() + ".log";

        // Prepare response to show a Save As dialogue with report.
        FacesContext facesContext = FacesContext.getCurrentInstance();
        ExternalContext externalContext = facesContext.getExternalContext();
        externalContext.setResponseContentType("application/octet-stream");
        externalContext.setResponseHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");

        // Write report to response body.
        output.writeTo(externalContext.getResponseOutputStream());

        // Inform JSF that response is completed and it thus doesn't have to navigate.
        facesContext.responseComplete();
    }
}
